home *** CD-ROM | disk | FTP | other *** search
/ internet.au CDrom 38 / netcd38.iso / FREEPROG / MAC / audio / macamp.hqx / MacAmp 1.0b6 ƒ / Plugin Programming / LevelMeter ƒ / Source / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-05  |  8.7 KB  |  358 lines

  1. /*
  2.     LevelMeter Visual Plugin Example
  3.     
  4.             Sample visual plugin to demonstrate MacAmp visual plugin API and additional tricks,
  5.             including access of the plugin resource fork, initializing the plugin info structure on
  6.             startup and more.
  7.             
  8.             You can use any portions of this code freely in your plugins without any restrictions.
  9.  
  10.     By: Slava Karpenko (slava@macamp.com)    9/2/98
  11.         @soft
  12.         
  13. */
  14.  
  15. #include "visual.h"
  16.  
  17. // Some useful defines.
  18. #define MIN(a,b)    (((a)<(b))?(a):(b))
  19. #define MAX(a,b)    (((a)>(b))?(a):(b))
  20. #define ABS(a)        ((a)<0?-(a):(a))
  21.  
  22. // This is the gPlugInfo block - a place where MacAmp gets initial information about your plugin.
  23. // Make sure to set the fragment's entry point to gPlugInfo to make it accessible for the MacAmp routines.
  24.  
  25. VPInfoBlock gPlugInfo =
  26. {
  27.     VP_API_VERSION,                // Should be always VP_API_VERSION
  28.     plugVisual,                    // Should be always plugVisual (otherwise what are we doing here? =)
  29.     
  30.     nil,                        // We have no flags
  31.     nil,                        // We have no global refcon.
  32.     "\pLevelMeter",                // What's our name to display in the Plugins menu?
  33.     
  34.                                 // Function pointers. Use nil if you don't use something.
  35.     PlugInitialize,
  36.     PlugTerminate,
  37.     PlugProcess,
  38.     PlugMacEvent,
  39.     PlugKeyDown,        // (unused in this example)
  40.     PlugIdle,            // (unused in this example)
  41.     PlugSettings,        // (unused in this example)
  42.     PlugAbout
  43. };
  44.  
  45. // These are globals.
  46. static long ticks;        // tick count variable to keep some sort of synch.
  47. static short left;        // left and right channel values (0<=x<=20)
  48. static short right;
  49. static short refnum;    // plugin resource fork refnum
  50.  
  51. // dirty hack.
  52. static Rect gScreenBounds = { 0, 0, 624, 832 };
  53.  
  54. // Other function prototypes
  55. void ProcessMP3(short chan, const double* stream);
  56. void ProcessMP2(short chan, const double* stream);
  57. void DrawMeters(WindowPtr wind);
  58. OSErr PlugLoadMyself(void);
  59. void PlugUnloadMyself(void);
  60.  
  61. /* 
  62.     PlugLoadMyself
  63.  
  64.     Called when your plugin fragment is loaded in memory. You may wish to change gPlugInfo fields here, or
  65.     do something else like opening your global preferences. Take a look at the PPC Linker panel in the target settings
  66.     to get an idea how it's done.
  67.     
  68. */
  69. OSErr PlugLoadMyself(void)
  70. {
  71.     return noErr;
  72. }
  73.  
  74. /* 
  75.     PlugUnloadMyself
  76.  
  77.     Called when MacAmp is about to quit and dispose all plugins. Dispose any global stuff you allocated in PlugLoadMyself
  78.     etc.
  79.     
  80. */
  81. void PlugUnloadMyself(void)
  82. {
  83.     return;
  84. }
  85.  
  86. /* 
  87.     PlugInitialize
  88.  
  89.     Called every time use selects your plugin from the Plugins menu. You need to allocate and display a window here,
  90.     init your variables, and do whatever you want, like set the refnum if you need it.
  91.     
  92.     This function uses FSSpec to itself that MacAmp provides to it to gain access to its resource fork.
  93.     
  94.     Other than that, everything is hard-coded and is definitly not an example of good programming =P
  95. */
  96. OSErr    PlugInitialize(WindowPtr* window, FSSpecPtr file, UInt32*)
  97. {
  98.     Rect bounds = { 40, 10, 49, 70 };    // guess what this is, it's window coordinates. Yuck. =)
  99.     GrafPtr    port;
  100.     
  101.     GetPort(&port);
  102.     
  103.     // create a new window with floating look as included in MacOS 7.6+ (WDEF id 124)
  104.     *window = NewCWindow(nil,&bounds,"\p",true,1985,(WindowPtr)-1,true,nil);
  105.     
  106.     if (!*window)
  107.         return visNoMemory;
  108.     
  109.     SetPort(*window);
  110.     BackColor(blackColor);
  111.     PenSize(1, 4);
  112.     ForeColor(greenColor);
  113.     SetPort(port);
  114.  
  115.     // init our variables.
  116.     left = right = 0;
  117.     ticks = TickCount();
  118.  
  119.     // draw zeroes initially
  120.     DrawMeters(*window);
  121.  
  122.     // Open our resource fork and save the refnum for closing it (we are a well-behaved plugin, right? ;)
  123.     refnum = FSpOpenResFile(file, fsRdPerm);
  124.  
  125.     return visNoErr;
  126. }
  127.  
  128. /* 
  129.     PlugTerminate
  130.  
  131.     Called when user deselects your plugin, MacAmp quits or in the case if you have passed visTerminate/visNoMemory error.
  132.     You should dispose your window here & clean up the mess.
  133. */
  134. OSErr    PlugTerminate(WindowPtr window, UInt32*)
  135. {
  136.     if (window != nil)
  137.         DisposeWindow(window);
  138.     
  139.     // Close our resource fork.
  140.     if (refnum != -1)
  141.         FSClose(refnum);
  142.         
  143.     return visNoErr;
  144. }
  145.  
  146. /* 
  147.     PlugProcess
  148.  
  149.     The heart of the visual plugin. It means your plugin needs to analyze the stream and display whatever you want.
  150.     
  151.     chan is the number of channels.
  152.     stream is the sound data, which has the size of [2][32][dataSize]. For now dataSize==18 means layer III files,
  153.     dataSize == 36 means layer II files. Sound data is separated by channels, so stream[0] would be left, and stream[1] -
  154.     right channel.
  155.     
  156.     You should never ever modify the contents of the stream pointer. Doing so will affect the playback.
  157.     [On the other hand, if you know what you're doing, you CAN modify the data stream. Doing so will change the sound.
  158.     So with a little knowledge you can turn a visual plugin into a sound plugin (make a new equalizer ;)]
  159. */
  160. OSErr    PlugProcess(WindowPtr window, short chan, const double* stream, short dataSize, UInt32*)
  161. {
  162.     if (TickCount() - ticks > 1)
  163.     {
  164.         if (dataSize == 18)
  165.             ProcessMP3(chan, stream);
  166.         else
  167.             ProcessMP2(chan, stream);
  168.             
  169.         DrawMeters(window);
  170.         
  171.         left--;
  172.         right--;
  173.         ticks = TickCount();
  174.     }
  175.     
  176.     return visNoErr;
  177. }
  178.  
  179. /* 
  180.     PlugMacEvent
  181.  
  182.     Process a mac event that is related to the window (activate/deactivate, update, mouseDown).
  183.     
  184.     You can do whatever you want, but remember that if you don't handle update events, that will screw up the whole
  185.     MacAmp window update process.
  186. */
  187. OSErr    PlugMacEvent(WindowPtr window, EventRecord* event, UInt32*)
  188. {
  189.     OSErr    result = visNoErr;
  190.     switch (event->what)
  191.     {
  192.         case updateEvt:
  193.             BeginUpdate(window);
  194.             DrawMeters(window);
  195.             EndUpdate(window);
  196.             break;
  197.             
  198.         case mouseDown:
  199.             {
  200.                 WindowPtr    wind;
  201.                 short thePart = FindWindow(event->where, &wind);
  202.                 switch (thePart)
  203.                 {
  204.                     case inDrag:
  205.                         // ugly hack. it shoulkd be qd.screenBits.bounds.
  206.                         DragWindow(wind, event->where, &gScreenBounds);
  207.                         break;
  208.                     
  209.                     case inGoAway:
  210.                         if (TrackGoAway(wind, event->where))
  211.                             result = visTerminate;            // if user clicked the close box, shut ourself down.
  212.                         break;
  213.                     
  214.                     case inContent:
  215.                         // hehe, max out everything
  216.                         left = right = 20;
  217.                         DrawMeters(wind);
  218.                         break;
  219.                 }
  220.                 
  221.             }
  222.             break;
  223.             
  224.         default:
  225.             break;
  226.     }
  227.     return result;
  228. }
  229.  
  230. /* 
  231.     PlugAbout
  232.  
  233.     Called when a user selects "About the Plugin" from the menu. You should display some sort of about box, 
  234.     do some sort of an effect or whatever you feel like it.
  235. */
  236. OSErr    PlugAbout(WindowPtr, UInt32*)
  237. {
  238.     NoteAlert(1234, nil);
  239.     return visNoErr;
  240. }
  241.  
  242. /* 
  243.     PlugIdle
  244.  
  245.     Called whenever MacAmp gets some spare time. It's a good place to decrement your values, draw the stuff etc.
  246.     
  247.     Called only if flagGetIdle is set.
  248. */
  249. OSErr    PlugIdle(WindowPtr window, UInt32* refcon)
  250. {
  251. #pragma unused (window, refcon)
  252.     return visNoErr;
  253. }
  254.  
  255. /* 
  256.     PlugKeyDown
  257.  
  258.     Called when a user presses a button, and after it was processed by MacAmp. Keep in mind that no matter if it
  259.     was processed by MacAmp or not, your plug still gets it. So if you want tto have some keyboard control, try to
  260.     use unused keys.
  261.     
  262.     Called only if flagGetKeyDown is set.
  263. */
  264. OSErr    PlugKeyDown(WindowPtr window, char key, short modifiers, UInt32* refcon)
  265. {
  266. #pragma unused (window, key, modifiers, refcon)
  267.     return visNoErr;
  268. }
  269.  
  270. /* 
  271.     PlugSettings
  272.  
  273.     Called when user selects your plugin from the Settings submenu. Only used if you have declared that
  274.     you support settings (flagHasSettings is set).
  275.     
  276.     You should display the settings dialog here, or do whateverr you feel like. =) Just remember that when user
  277.     chooses settings (s)he expects some interactino with the plugin, like the dialog or like that.
  278. */
  279. OSErr    PlugSettings(WindowPtr window, UInt32* refcon)
  280. {
  281. #pragma unused (window, refcon)
  282.     return visNoErr;
  283. }
  284.  
  285. // The following two functions are examples of analyzing the data stream.
  286. void ProcessMP3(short chan, const double* stream)
  287. {
  288.     int z;
  289.     
  290.     double sum1 = 0.0;
  291.     double sum2 = 0.0;
  292.         
  293.     if (chan == 2)
  294.     {
  295.         for (z = 1; z < 20; z ++)
  296.           sum1 += stream[z];
  297.         for (z = 1; z < 20; z ++)
  298.           sum2 += stream[32*18+z];
  299.     } else {
  300.         for (z = 1; z < 20; z ++)
  301.          sum1 += stream[z];
  302.         sum2 = sum1;
  303.     }
  304.     
  305.     sum1 = ABS(sum1) * 20.0;
  306.     sum1 = MIN(20.0, MAX(0.0, sum1));
  307.     left = MAX(left, sum1);
  308.  
  309.     sum2 = ABS(sum2) * 20.0;
  310.     sum2 = MIN(20.0, MAX(0.0, sum2));
  311.     right = MAX(right, sum2);
  312. }
  313.  
  314. void ProcessMP2(short chan, const double* stream)
  315. {
  316.     short z;
  317.     
  318.     double sum1 = 0.0;
  319.     double sum2 = 0.0;
  320.         
  321.         if (chan == 2)
  322.         {
  323.             for (z = 0; z < 20; z ++)
  324.               sum1 += stream[z];
  325.             for (z = 0; z < 20; z ++)
  326.               sum2 += stream[32*36+z];
  327.         } 
  328.         else 
  329.         {
  330.             for (z = 0; z < 20; z ++)
  331.               sum1 += stream[z];
  332.             sum2 = sum1;
  333.         }
  334.         
  335.     sum1 = ABS(sum1) * 10;
  336.     sum1 = MIN(20.0, MAX(0.0, sum1));
  337.     left = MAX(left, sum1);
  338.  
  339.     sum2 = ABS(sum2) * 10;
  340.     sum2 = MIN(20.0, MAX(0.0, sum2));
  341.     right = MAX(right, sum2);
  342. }
  343.  
  344. // And this is a really simple function that draws the meter bars.
  345. void DrawMeters(WindowPtr wind)
  346. {
  347.     GrafPtr    oldPort;
  348.     
  349.     GetPort(&oldPort);
  350.     SetPort(wind);
  351.     EraseRect(&wind->portRect);
  352.     MoveTo(0,0);
  353.     Line(left * 3, 0);
  354.     MoveTo(0, 5);
  355.     Line(right * 3, 0);
  356.     
  357.     SetPort(oldPort);
  358. }